
package janino.analisador;

import java.io.IOException;
import java.io.Reader;

public class UnicodeUnescapeReader extends FilterReader {

    public UnicodeUnescapeReader(Reader in) {
        super(in);
    }

    public int read() throws IOException {
        int c;

        // Read next character.
        if (this.unreadChar == -1) {
            c = this.in.read();
        } else {
            c = this.unreadChar;
            this.unreadChar = -1;
        }

        // Check for backslash-u escape sequence, preceeded with an even number
        // of backslashes.
        if (c != '\\' || this.oddPrecedingBackslashes) {
            this.oddPrecedingBackslashes = false;
            return c;
        }

        // Read one character ahead and check if it is a "u".
        c = this.in.read();
        if (c != 'u') {
            this.unreadChar = c;
            this.oddPrecedingBackslashes = true;
            return '\\';
        }

        // Skip redundant "u"s.
        do {
            c = this.in.read();
            if (c == -1) {
                throw new IOException("Incomplete escape sequence");
            }
        } while (c == 'u');

        // Decode escape sequence.
        char[] ca = new char[4];
        ca[0] = (char) c;
        if (this.in.read(ca, 1, 3) != 3) {
            throw new IOException("Incomplete escape sequence");
        }
        try {
            return 0xffff & Integer.parseInt(new String(ca), 16);
        } catch (NumberFormatException ex) {
            throw new IOException("Invalid escape sequence \"\\u" + new String(ca) + "\"");
        }
    }

    public int read(char[] cbuf, int off, int len) throws IOException {
        if (len == 0) {
            return 0;
        }
        int res = 0;
        do {
            int c = this.read();
            if (c == -1) {
                break;
            }
            cbuf[off++] = (char) c;
        } while (++res < len);
        return res == 0 ? -1 : res;
    }

    private int unreadChar = -1; // -1 == none

    private boolean oddPrecedingBackslashes = false;

}
